<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>promise对象</title>
</head>

<body>

</body>
<script>
  // Promise.any  Promise.allSettled  Promise.finally()
  /*
    await可以和for...of循环一起使用，以串行的方式运行异步操作
      async function process(array) {
        for await (let i of array) {
          // doSomething(i);
      }
    }
  */
  // JavaScript 异步代码的几个推荐做法

  /*
    1.不建议将 async 函数传递给 new Promise 的构造函数。
    new Promise(async (resolve, reject) => { })
    在 Promise 的构造函数里去使用 async ，那么包装个 Promise 可能就是没啥必要的。另外，如果 async 函数抛出了异常，新构造的 promise 实例并不会 reject ，那么这个错误就捕获不到了
    
    new Promise((resolve, reject) => { }) 
  */

  /*
    2.不建议在循环里使用 await，有这种写法通常意味着程序没有充分利用 JavaScript 的事件驱动。
    for (let url of urls) {
      let response = await fetch(url);
    }

    建议将这些异步任务改为并发执行，这可以大大提升代码的执行效率
    let resarr = []
    for (const url of urls) {
      const res = fetch(url)
      resarr.push(res)
    }

    await Promise.all(resarr)
  */

  /*
    3.不建议在 Promise 构造函数中返回值，Promise 构造函数中返回的值是没法用的，并且返回值也不会影响到 Promise 的状态
    new Promise((resolve, reject) => {
      return res
    })

    正常的做法是将返回值传递给 resolve，如果出错了就传给 rejec
    new Promise((resolve, reject) => {
      resolve(result)
    })
  */
</script>
<script>
  // 4.不建议将赋值操作和 await 组合使用，这可能会导致条件竞争。看看下面的代码，你觉得 totalPosts 最终的值是多少
  "use strict"; {
    let totalPosts = 0
    // 商品数组
    let list = [{ id: 1, value: 5 }, { id: 2, value: 3 }]
    // 睡眠函数
    let sleep = time => {
      return new Promise(resolve => setTimeout(resolve, time))
    }
    // 获取到数组的value值
    let getListValue = async id => {
      await sleep(~~(Math.random() * 1000))
      return list.find(v => v.id === id).value
    }
    // 对值进行累加
    // 不建议将赋值操作和 await 组合使用，这可能会导致条件竞争
    let add = async id => {
      totalPosts += await getListValue(id)
    }

    // 建议将赋值操作和 await 分开使用
    let add1 = async id => {
      let res = await getListValue(id)
      totalPosts += res
    }

    (async () => {
      await Promise.all([add(1), add(2)])
      // await Promise.all([add1(1), add1(2)])
      console.info(`%c得到结果: ${totalPosts}`, `color: #19be6b; font-family: kaiti; font-size: 30px;`)
    })()
  }
</script>
<script>
  "use strict"; {
    // 返回异步结果时不一定要写 await ，如果你要等待一个 Promise，然后又要立刻返回它，这可能是不必要的
    // async () => {
    //   return await getUser(userId);
    // }

    // 从一个 async 函数返回的所有值都包含在一个 Promise 中，你可以直接返回这个 Promise
    // async () => {
    //   return getUser(userId);
    // }

    // 如果外面有 try...catch 包裹，删除 await 就捕获不到异常了，在这种情况下，建议明确一下意图，把结果分配给不同行的变量
    // async () => {
    //   try {
    //     return await getUser(userId);
    //   } catch (err) {
    //     // Handle getUser error
    //   }
    // }

    // 建议这样写
    // async () => {
    //   try {
    //     const user = await getUser(userId);
    //     return user;
    //   } catch (error) {
    //     // Handle getUser error
    //   }
    // }
  }
</script>
<script>
  "use strict"; {
    // reject Promise 时强制使用 Error 对象，这样可以更方便的追踪错误堆栈。
    // Promise.reject("有错误")
    // 建议这样写
    // Promise.reject(new Error("有错误"))
  }
</script>
<script>
  "use strict"; {
    // myPromise()
    //   .then(() => { })

    // 建议 Promise 附加异常处理的代码
    // myPromise()
    //   .then(() => { })
    //   .catch(() => { })
  }
</script>
<script>
  // 判断函数是否为promise
  let isPromise = obj => {
    // !!obj 有实际含义的变量才执行方法，变量null，undefined和''空串都为false
    return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
    // 初始promise 或 promise.then返回的
  }
</script>

</html>